package cn.nohan.funplay.module.member.mongo.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.json.JSONUtil;
import cn.nohan.funplay.module.member.mongo.entity.*;
import cn.nohan.funplay.module.member.mongo.mapper.MongoCommentEntityMapper;
import cn.nohan.funplay.module.member.mongo.mapper.MongoDynamicEntityMapper;
import cn.nohan.funplay.module.member.mongo.mapper.MongoUserTrajectoryEntityMapper;
import com.mongodb.BasicDBObject;
import com.mongodb.client.model.BsonField;
import com.mongoplus.aggregate.AggregateWrapper;
import com.mongoplus.aggregate.LambdaAggregateWrapper;
import com.mongoplus.aggregate.pipeline.Accumulators;
import com.mongoplus.conditions.interfaces.Projection;
import com.mongoplus.conditions.query.QueryChainWrapper;
import com.mongoplus.conditions.query.QueryWrapper;
import com.mongoplus.conditions.update.UpdateWrapper;
import com.mongoplus.mapper.BaseMapper;
import com.mongoplus.model.PageParam;
import com.mongoplus.model.PageResult;
import com.mongoplus.model.geo.Coordinate;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.bson.*;
import org.bson.conversions.Bson;
import org.bson.types.ObjectId;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.geo.Metrics;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.NearQuery;
import org.springframework.stereotype.Service;

import javax.swing.*;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author caozhipeng
 * @date 2025/7/11
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class DynamicService {

    private final MongoDynamicEntityMapper mongoDynamicEntityMapper;
    private final MongoCommentEntityMapper mongoCommentEntityMapper;

    private final BaseMapper baseMapper;

    private final MongoUserTrajectoryEntityMapper mongoUserTrajectoryEntityMapper;

    private final MongoTemplate mongoTemplate;

    public List<Document> test(){
        LambdaAggregateWrapper<MongoDynamicEntity> aggregate=new LambdaAggregateWrapper<MongoDynamicEntity>();
        aggregate.unwind(MongoDynamicEntity::getTags);
        aggregate.group(MongoDynamicEntity::getTags, Accumulators.sum());
        aggregate.sortDesc("count");
        aggregate.limit(5);
        aggregate.project(false,new Projection("name","$_id"),new Projection("count","$count"));
        List<Document> result = mongoDynamicEntityMapper.list(aggregate,Document.class);
        return result;
    }

    public Document getOneUser(Long userId){
        QueryWrapper<MongoUserTrajectoryEntity> queryChainWrapper=new QueryWrapper<MongoUserTrajectoryEntity>();
        queryChainWrapper.eq(MongoUserTrajectoryEntity::getUserId,userId);
        return mongoUserTrajectoryEntityMapper.one(queryChainWrapper,Document.class);
    }

    public MongoUserTrajectoryEntity getOneUser2(Long userId){
        QueryWrapper<MongoUserTrajectoryEntity> queryChainWrapper=new QueryWrapper<MongoUserTrajectoryEntity>();
        queryChainWrapper.eq(MongoUserTrajectoryEntity::getUserId,userId);
        return mongoUserTrajectoryEntityMapper.one(queryChainWrapper,MongoUserTrajectoryEntity.class);
    }

    public void save(Long userId, Double longitude, Double latitude){
         mongoUserTrajectoryEntityMapper.save(new MongoUserTrajectoryEntity(userId,new GeoJsonPoint(longitude,latitude)));
    }

    public GeoResults<Document> getNearUser(){
        Double maxDistance = 5d;
        Double minDistance = 0.1d;
        // 2. 构建地理空间查询
        NearQuery nearQuery = NearQuery.near(new GeoJsonPoint(120.89531932113306,31.97006002059206))
                .maxDistance(new Distance(maxDistance , Metrics.KILOMETERS))
                .minDistance(new Distance(minDistance , Metrics.KILOMETERS))
                .spherical(true)
                .distanceMultiplier(1)
                .limit(10);

        // 3. 执行查询
        GeoResults<Document> results = mongoTemplate.geoNear(nearQuery, Document.class,"user_trajectory");

        return results;
    }

    public MongoDynamicEntity getById(String id){
        return mongoDynamicEntityMapper.getById(id);
    }
    public Document getById2(String id){
        return  mongoDynamicEntityMapper.getById(id, Document.class);
    }

    public List<Long>   getSupperUserList(){
        List<Long> userIds = new ArrayList<>();
        userIds.add(1L);
        userIds.add(32L);
        userIds.add(31L);

        AggregateWrapper aggregateWrapper = new AggregateWrapper();
        aggregateWrapper.match(new QueryWrapper<MongoDynamicEntity>().in("userId", userIds));

        List<BsonString> eqList = new ArrayList<>();
        eqList.add(new BsonString("$dynamicId"));
        eqList.add(new BsonString("$$dynamicId"));

        BsonDocument pipeline= new BsonDocument("$match",new BsonDocument("$expr",new BsonDocument("$eq",new BsonArray(eqList))));
        List<BsonDocument> pipelineList = new ArrayList<>();
        pipelineList.add(pipeline);

        BsonDocument bsonDocument = new BsonDocument("$lookup",new BsonDocument("from", new BsonString("support"))
                .append("let", new BsonDocument("dynamicId",new BsonDocument("$toString",new BsonString("$_id"))))
                .append("pipeline",new BsonArray(pipelineList))
                .append("as", new BsonString("supports")));

        aggregateWrapper.lookup(bsonDocument);
        aggregateWrapper.match(new BsonDocument("supports.userId", new BsonInt32(7)));
        aggregateWrapper.project(new Projection("userId", 1),new Projection("_id", 0));
        List<Document> userIdsList = baseMapper.aggregateList( "dynamic",aggregateWrapper,Document.class);
        if(CollUtil.isNotEmpty(userIdsList)){
           return userIdsList.stream().map(document -> document.getLong("userId")).distinct().collect(Collectors.toList());
        }
        return null;
    }

    public List<Document>   getSupperUserList2(){
        List<Long> userIds = new ArrayList<>();
        userIds.add(1L);
        userIds.add(32L);
        userIds.add(31L);

        AggregateWrapper aggregateWrapper = new AggregateWrapper();
        aggregateWrapper.match(new QueryWrapper<MongoDynamicEntity>().in("userId", userIds));

        List<BsonString> eqList = new ArrayList<>();
        eqList.add(new BsonString("$dynamicId"));
        eqList.add(new BsonString("$$dynamicId"));

        BsonDocument pipeline= new BsonDocument("$match",new BsonDocument("$expr",new BsonDocument("$eq",new BsonArray(eqList))));
        List<BsonDocument> pipelineList = new ArrayList<>();
        pipelineList.add(pipeline);

        BsonDocument bsonDocument = new BsonDocument("$lookup",new BsonDocument("from", new BsonString("support"))
                .append("let", new BsonDocument("dynamicId",new BsonDocument("$toString",new BsonString("$_id"))))
                .append("pipeline",new BsonArray(pipelineList))
                .append("as", new BsonString("supports")));

        aggregateWrapper.lookup(bsonDocument);
        aggregateWrapper.match(new BsonDocument("supports.userId", new BsonInt32(7)));
        aggregateWrapper.project(new Projection("userId", 1),new Projection("_id", 0));
        List<Document> userIdsList = baseMapper.aggregateList( "dynamic",aggregateWrapper,Document.class);
        return userIdsList;
    }

    public  List<Long> getLeftJoin(List<Long> userIds,Long currentUserId){
        AggregateWrapper aggregateWrapper = new AggregateWrapper();
//        aggregateWrapper.match(new QueryWrapper<MongoDynamicEntity>().in("userId", userIds));
        aggregateWrapper.lookup("support","dynamicId","id","supports");
        aggregateWrapper.match(new BsonDocument("supports.userId", new BsonInt64(currentUserId)));
        aggregateWrapper.group("$userId");
        aggregateWrapper.project(new Projection("userId", "$_id"),new Projection("_id", 0));
        aggregateWrapper.group(null, new BsonField("userIdList", new BsonDocument("$push", new BsonString("$userId"))));
        aggregateWrapper.project(new Projection("userIdList", 1),new Projection("_id", 0));

        Document document = baseMapper.aggregateOne(aggregateWrapper,MongoDynamicEntity.class,Document.class);
        log.info("document:{}", JSONUtil.toJsonStr(document));
        if(ObjUtil.isNotNull(document)){
            return document.getList("userIdList",Long.class);
        }
        return Collections.emptyList();
    }



    public List<MongoDynamicEntity> getList(){
        List<String> tags=new ArrayList<>();
        tags.add("原神圈");
        tags.add("骑行圈");
        QueryWrapper<MongoDynamicEntity> queryChainWrapper= new QueryWrapper<MongoDynamicEntity>();;
//        queryChainWrapper.eq("userId",31);
//        queryChainWrapper.in("tags",tags);
//        queryChainWrapper.or(true,new QueryWrapper<MongoDynamicEntity>().exists("publishLocation",false).or(true,new QueryWrapper<MongoDynamicEntity>().eq("publishLocation",1)));
        queryChainWrapper.like("content","键盘");
        return mongoDynamicEntityMapper.list(queryChainWrapper);
    }

    public void getGroupCount(){
        List<String> ids=new ArrayList<>();
        ids.add("673e7da8377cba2b9e00e449");
        ids.add("6742a65ade83eb6d87967a44");
        AggregateWrapper aggregateWrapper = new AggregateWrapper();
        aggregateWrapper.match(new QueryWrapper<>().in("dynamicId", ids));
        aggregateWrapper.group("$dynamicId", Accumulators.sum());
//        返回值重命名，顺序不能反
        aggregateWrapper.project(false,new Projection("dynamicId","$_id"),new Projection("count","$count"));

        List<MongoGroupResultDTO> userList = mongoCommentEntityMapper.getBaseMapper().aggregateList(aggregateWrapper, MongoCommentEntity.class, MongoGroupResultDTO.class);
        log.info("userList:{}",userList);
    }

    public List<MongoGroupResultDTO>  getCount(){
        AggregateWrapper aggregateWrapper = new AggregateWrapper();
        aggregateWrapper.match(new QueryWrapper<MongoCommentEntity>().exists("schoolCode", true));
        aggregateWrapper.group("$schoolCode", Accumulators.sum("count",1));
        aggregateWrapper.sortDesc("count");
        aggregateWrapper.limit(10);
//          返回值重命名，顺序不能反
        aggregateWrapper.project(false,new Projection("dynamicId","$_id"),new Projection("count","$count"));

        List<MongoGroupResultDTO>  countList = mongoDynamicEntityMapper.getBaseMapper().aggregateList(aggregateWrapper, MongoDynamicEntity.class, MongoGroupResultDTO.class);
        return countList;
    }

    public Boolean deleteById(String id){
        return mongoDynamicEntityMapper.removeById(id);
    }

    public  void initDynamicDeleted(){
        UpdateWrapper<MongoDynamicEntity> updateChainWrapper=new UpdateWrapper<MongoDynamicEntity>();
        updateChainWrapper.set("deleted",false);
        updateChainWrapper.exists("deleted",false);
        mongoDynamicEntityMapper.update(updateChainWrapper);
        log.info("================初始化动态deleted=false =================");
    }


}
